using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Web.UI;

namespace OpenWaves.Web
{
    public static class ControlExtensions
    {
        public static IEnumerable<Control> GetChildrenRecursively(this Control parent)
        {
            Contract.Requires<ArgumentNullException>(parent != null);
            Contract.Ensures(Contract.Result<IEnumerable<Control>>() != null);

            foreach (Control control in parent.Controls)
            {
                yield return control;
            }

            foreach (Control control in parent.Controls)
            {
                foreach (var descendant in control.GetChildrenRecursively())
                {
                    yield return descendant;
                }
            }
        }

        public static T GetFirstChildOfTypeOrDefault<T>(this Control parent)
        {
            Contract.Requires<ArgumentNullException>(parent != null);

            return parent.GetChildrenRecursively().OfType<T>().FirstOrDefault();
        }

        public static IEnumerable<Control> GetAncestors(this Control control)
        {
            Contract.Requires<ArgumentNullException>(control != null);
            Contract.Ensures(Contract.Result<IEnumerable<Control>>() != null);

            var p = control.Parent;
            while (p != null)
            {
                yield return p;
                p = p.Parent;
            }
        }

        public static Control FindControlRecursive(this Control control, string id)
        {
            Contract.Requires<ArgumentNullException>(control != null);
            Contract.Requires<ArgumentNullException>(id.IsNullOrWhiteSpace() == false);

            var ctrl = control.FindControl(id);

            if (ctrl == null)
            {
                foreach (Control child in control.Controls)
                {
                    ctrl = FindControlRecursive(child, id);
                    if (ctrl != null) 
                        break;
                }
            }

            return ctrl;
        }
    }
}